/*
	Project:	CoreEngine
	Author:		Dino Bojadzhievski
	File:		Transform2

	Defines common linear transformations in two-dimensional space.

	All performed with homogeneous coordinates (3D vectors and matrices).
	All angles expressed in degrees.
	Positive angles are counter-clockwise.

	Usage:
		1. Translate to origin.
		2. Perform transforms.
		3. Translate to starting point.
*/


#pragma once

#include "Matrix3.h"
#include "Vector3.h"
#include <math.h>

namespace CoreMath
{
	/* Rotation matrices. Use for transform concatenation. */

	Matrix3 GetRotationMatrix(const real angle)
	{
		real angleSin = sin(angle);
		real angleCos = cos(angle);

		real rawValue[3][3] =
		{
			angleCos, -angleSin, 0,
			angleSin, angleCos, 0,
			0, 0, 1
		};

		return Matrix3(rawValue);
	}

	Matrix3 GetTranslationMatrix(real dX, real dY)
	{
		real rawValue[3][3] =
		{
			1, 0, dX,
			0, 1, dY,
			0, 0, 1
		};

		return Matrix3(rawValue);
	}

	Matrix3 GetScalingMatrix(const real scaleX, const real scaleY)
	{
		real rawValue[3][3] =
		{
			scaleX, 0, 0,
			0, scaleY, 0,
			0, 0, 1
		};

		return Matrix3(rawValue);
	}

	Matrix3 GetShearingMatrix(const real shearX, const real shearY)
	{
		real rawValue[3][3] =
		{
			0, shearY, 0,
			shearX, 0, 0,
			0, 0, 1
		};

		return Matrix3(rawValue);
	}

	Matrix3 GetReflectionMatrix()
	{
		return GetScalingMatrix(1, -1);
	}

	Matrix3 GetProjectionMatrix(const Vector2& direction)
	{
		real rawValue[3][3] =
		{
			pow(direction.i, 2),	direction.i * direction.j,	0,
			direction.i*direction.j, pow(direction.j, 2),		0,
			0,						0,							1
		};

		return Matrix3(rawValue);
	}

	/* Elementary transforms. */

	void Translate(Vector3& vector, const real dX, const real dY)
	{
		vector = GetTranslationMatrix(dX, dY) * vector;
	}

	void Rotate(Vector3& vector, const real angle)
	{
		vector = GetRotationMatrix(angle) * vector;
	}	

	void Scale(Vector3& vector, const real scaleX, const real scaleY)
	{
		vector = GetScalingMatrix(scaleX, scaleY) * vector;
	}

	void Shear(Vector3& vector, const real shearX, const real shearY)
	{
		vector = GetShearingMatrix(shearX, shearY) * vector;
	}

	void Reflect(Vector3& vector)
	{
		vector = GetReflectionMatrix() * vector;
	}

	void Project(Vector3& vector, const Vector2& direction)
	{
		vector = GetProjectionMatrix(direction) * vector;
	}
}